#ifndef _H_I_Runner_H_
#define _H_I_Runner_H_

#include "../typedefine.h"
#ifdef _USING_CLI
#include "core/CRunnerHandleMsgCallback.h"
#else
#include <mutex>
#include <atomic>
#endif
#include "../collection.h"
#include "../timer.h"
#include "ServiceDelegate.h"
#include "CService.h"
#include "IServiceComponent.h"
#include "CNewBackendMsg.h"
#include "SRunnerUpdateUID.h"

namespace QWER
{
	QCLASS IServiceFrontend;
	QCLASS IServiceBackend;
	QCLASS IServiceMsg;
	QCLASS IToServiceFrontendMsg;
	QCLASS IToServiceBackendMsg;

	QDLL_EXPORT QCLASS IRunner QABSTRACT
	{
		NON_COPYABLE(IRunner)
	public:
		IRunner();
#ifndef _USING_CLI
		~IRunner();
#endif
		inline PTR(CTimerMgr) GetTimerMgr(){ return TO_PTR(m_oTimerMgr); }
		inline PTR(CPromiseMgr) GetPromiseMgr(){ return m_poPromiseMgr; }

		UINT32 Poll(UINT64 qwDeltaMilliSeconds);
		void RunApp(CONST_PTR_OR_REF(DNewApplication) cbNewApplication);
		QTEMPLATE<typename FRONTEND, typename BACKEND> QWHERE(FRONTEND: IServiceFrontend) QWHERE(BACKEND: IServiceBackend)
		PTR(CService<FRONTEND>) RunService(CONST_PTR_OR_REF(DNewServiceFrontend<FRONTEND>) cbNewFrontend, CONST_PTR_OR_REF(DNewServiceBackend<BACKEND>) cbNewBackend)
		{
			PTR(CService<FRONTEND>) poRet = QNEW CService<FRONTEND>(cbNewFrontend, m_oRunnerPipe);
#ifndef _USING_CLI
			m_oServiceMgr.Push(poRet);
#endif
			CNewBackendMsg<BACKEND>* poMsg = new CNewBackendMsg<BACKEND>(*this, *poRet, cbNewBackend);
			m_oRunnerPipe.Push(poMsg);
			return poRet;
		}
        SRunnerUpdateUID Register(const DRunnerUpdateFunc& cbUpdate);
        SRunnerUpdateUID Register(DRunnerUpdateFunc&& cbUpdate);
        void Unregister(const SRunnerUpdateUID& sUID);

	private:
		CUnOrderedMap(PTR(IService), PTR(IServiceFrontend)) m_oConnectedFrontends;
#ifndef _USING_CLI
		CMPSCQueue<PTR(IService)> m_oServiceMgr;
		CVector(PTR(IApplication)) m_oApplicationMgr;
#endif
		CMPSCQueue<PTR(IServiceMsg)> m_oRunnerPipe;
		CTimerMgr m_oTimerMgr;
		PTR(CPromiseMgr) m_poPromiseMgr = NULL_PTR;
        std::list<DRunnerUpdateFunc> m_oRunnerUpdateFuncList;

#ifdef _USING_CLI
	internal:
#else
	private:
		friend class IServiceFrontend;
		friend class IServiceBackend;
		friend class IApplication;
		friend class CServiceBackendHelper;
		friend class CServiceFrontendHelper;
		friend class CApplicationHelper;
		friend class IService;
		friend class CNewApplicationMsg;
#endif
		PTR(IServiceFrontend) _Connect(IService* poService, CONST_PTR_OR_REF(DNewServiceFrontend<IServiceFrontend>) cbNewFrontend);
		inline PTR(CMPSCQueue<PTR(IServiceMsg)>) _Pipe() { return &m_oRunnerPipe; }
		void _AddApp(PTR(IApplication) poApp) { m_oApplicationMgr.push_back(poApp); }

	};
}

#endif
